﻿#include "effects/noise.h"

#include "common.h"
#include "texture.h"
#include "shader.h"
#include "context.h"
#include "target.h"
#include <exception>

namespace anip
{
	NoiseEffect::NoiseEffect(int w, int h, bool isColor) :
		_iscolor(isColor), _shader(nullptr)
	{
		_name = _iscolor ? "noise" : "noise (monochrome)";
		floatParams = new Parameter<float>[1];
		texOutputs = new TextureParameter[1];
		texOutputs[0].w = w;
		texOutputs[0].h = h;
	}

	void NoiseEffect::initialize()
	{
		assert(texParams[0].w > 0 && texParams[0].h > 0);

		if (_target != nullptr)
		{
			_target->finalize();
			delete _target;
		}

		if (_shader != nullptr)
		{
			_shader->finalize();
			delete _shader;
		}

		_target = new RenderBuffer(texOutputs[0].w, texOutputs[0].h);

		string source =
			"in vec2 pos;";
		if (floatParams[0].mapped)
			source.append("uniform sampler2D seed;");
		else
			source.append("uniform float seed;");
		source.append(
			"void main()"
			"{");
		if (floatParams[0].mapped)
			source.append("vec2 p = pos + sampler2D(seed, pos).rr;");
		else
			source.append("vec2 p = pos + vec2(seed);");
		source.append(
			"vec3 q = vec3(dot(p, vec2(127.1, 311.7)),"
							"dot(p, vec2(269.5, 183.3)),"
							"dot(p, vec2(419.2, 371.9)));"
			"vec4 res = vec4(fract(sin(q) * 43758.5453), 0);");
		if (_iscolor)
			source.append("gl_FragColor = res;}");
		else
			source.append("float t = dot(res, vec3(1.0/3));"
				"gl_FragColor = vec4(t, t, t, 0);}");

		_shader = Shader::load(basicVert, source.c_str());
	}

	void NoiseEffect::process(const Context& cxt)
	{
		_target->beginRender();

		_shader->use();
		if (floatParams[0].mapped)
			_shader->set("seed", *floatParams[0].map, 1);
		else
			_shader->set("seed", floatParams[0].value);
		cxt.fill();

		texOutputs[0].value = &_target->getTexture();

		_target->endRender();
	}

	void NoiseEffect::finalize()
	{
		_target->finalize();
		_shader->finalize();
		delete _target;
		delete _shader;
		delete floatParams;
		delete texOutputs;
	}
}